#ifndef __CONFIG_GET_H__
#define __CONFIG_GET_H__

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

//return 0 ok
//return -1 not found key
//return -2 outbuf too small
#define config_get(file, key, output, output_buf_len, verbose) ({ \
    const char *_f = file, *_k = key; char *_output = output; int _len = output_buf_len, _verbose = verbose; \
    int _ok = -1, name_len = strlen(_k); char _line[10000]; \
    FILE *fp = fopen(_f, "r"); \
    if (fp == NULL) { \
        if (_verbose > 1) LOGERR("open %s error[%m]\n", _f); \
    } else { \
        while (_ok == -1 && fgets(_line, sizeof(_line), fp)) { \
            if (strncmp(_line, _k, name_len) == 0) { \
                if (_line[name_len] != ' ' && _line[name_len] != '=') continue; \
                char *p = strchr(_line, '='); \
                if (!p) continue; \
                p++; \
                while (*p == ' ') p++; \
                int i = 0; \
                _output[0] = 0;  \
                while(*p) { \
                    if (i >= _len) { _ok = -2; break; } \
                    if (*p == '\r' || *p == '\n') { break; } \
                    _ok = 0; \
                    _output[i] = *p;  \
                    i++; p++; \
                    _output[i] = 0; \
                } \
            }    \
        }    \
        if (_ok == 0 && _verbose > 1) printf("%s = %s [load from %s]\n", _k, _output, _f); \
        fclose(fp); \
    } _ok; })

#define config_get_num(   f, k, v, ver) ({ int      *_v = v; int ret = -1; char line[10000]; sprintf(line, "%d"     , *_v); if (config_get(f, k, line, 10000, ver) == 0) { *_v = atoi(line         ); ret = 0; } ret; })
#define config_get_uint16(f, k, v, ver) ({ uint16_t *_v = v; int ret = -1; char line[10000]; sprintf(line, "%u"     , *_v); if (config_get(f, k, line, 10000, ver) == 0) { *_v = strtoul(line, 0, 0); ret = 0; } ret; })
#define config_get_uint32(f, k, v, ver) ({ uint32_t *_v = v; int ret = -1; char line[10000]; sprintf(line, "%u"     , *_v); if (config_get(f, k, line, 10000, ver) == 0) { *_v = strtoul(line, 0, 0); ret = 0; } ret; })
#define config_get_uint64(f, k, v, ver) ({ uint64_t *_v = v; int ret = -1; char line[10000]; sprintf(line, "%"PRIu64, *_v); if (config_get(f, k, line, 10000, ver) == 0) { *_v = strtoull(line, 0, 0); ret = 0; } ret; })

#define CONFIG_FILE_CONTENT_MAX 1000000
static inline int config_put(const char *path, const char *key, const char *value, pthread_mutex_t *lock)
{
    if (lock) pthread_mutex_lock(lock);
    char kmisc[256]; snprintf(kmisc, sizeof(kmisc) - 1, "%s=", key); kmisc[sizeof(kmisc) - 1] = 0; int kmisc_len = strlen(kmisc);
    int value_len = strlen(value);
    char *content = malloc(CONFIG_FILE_CONTENT_MAX); int  content_len = 0;
    char line[10000];
    int put_ok = 0;
    int ret = -1;
    FILE *fp = NULL;
    if (content == NULL) { printf("fail to malloc %s %s %u\n", __FILE__, __func__, __LINE__); } else {
        fp = fopen(path, "r");
        if (fp) {
            while (fgets(line, sizeof(line), fp)) {
                if (put_ok == 0 && strncmp(line, kmisc, kmisc_len) == 0) {
                    if (content_len + kmisc_len > CONFIG_FILE_CONTENT_MAX) { goto out; } memcpy(content + content_len, kmisc, kmisc_len); content_len += kmisc_len;
                    if (content_len + value_len > CONFIG_FILE_CONTENT_MAX) { goto out; } memcpy(content + content_len, value, value_len); content_len += value_len;
                    if (content_len + 1         > CONFIG_FILE_CONTENT_MAX) { goto out; } memcpy(content + content_len, "\n", 1);          content_len += 1;
                    put_ok = 1;
                } else {
                    int line_len = strlen(line); if (content_len + line_len > CONFIG_FILE_CONTENT_MAX) { goto out; } strcat(content, line); content_len += strlen(line);
                }
            }
            fclose(fp); fp = NULL;
        }
        if (put_ok == 0) {
            if (content_len + kmisc_len > CONFIG_FILE_CONTENT_MAX) { goto out; } memcpy(content + content_len, kmisc, kmisc_len); content_len += kmisc_len;
            if (content_len + value_len > CONFIG_FILE_CONTENT_MAX) { goto out; } memcpy(content + content_len, value, value_len); content_len += value_len;
            if (content_len + 1         > CONFIG_FILE_CONTENT_MAX) { goto out; } memcpy(content + content_len, "\n", 1);          content_len += 1;
        }
        fp = fopen(path, "w"); if (fp == NULL) { printf("fail to fopen(%s, w)[%m] %s %s %u\n", path, __FILE__, __func__, __LINE__); } else { fwrite(content, 1, content_len, fp); fclose(fp); fp = NULL; }

        free(content); content = NULL;
        ret = 0;
    }
out:
    if (content) free(content);
    if (fp) fclose(fp);
    if (lock) pthread_mutex_unlock(lock);
    return ret;;
}

#endif

